package org.micode.libs.servlet.base;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.micode.common.base.BaseController;
import org.micode.common.config.ApplicationConfig;
import org.micode.common.consts.HttpHeadConsts;
import org.micode.common.domain.ApiResult;
import org.micode.common.domain.base.IUserCache;
import org.micode.common.enums.ResultEnum;
import org.micode.common.utils.StringExtUtils;
import org.micode.common.weixin.WxUtils;
import org.micode.libs.servlet.utils.HttpContextUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.Validator;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * 控制类基类
 */
@Slf4j
public abstract class AbstractWebController
        extends BaseController<HttpServletRequest> {

    @Autowired
    protected HttpServletRequest request;

    @Autowired
    protected HttpServletResponse response;

    @Autowired
    protected Validator validator;

    protected String getRequestReferer() {
        return request.getHeader("referer");
    }

    protected boolean verifyRequestReferer(String appId) {
        String referer = getRequestReferer();
        return verifyRequestReferer(appId, referer);
    }

    protected boolean verifyRequestReferer(String appId, String referer) {
        return WxUtils.verifyRequestReferer(appId, referer);
    }

    @Override
    protected String getToken(HttpServletRequest webObject) {
        return HttpContextUtils.getToken(request);
    }

    @Override
    protected String getLoginClientApp(HttpServletRequest webObject) {
        String clientApp = HttpContextUtils.getClientApp(request);
        if (StringExtUtils.isAnyEmpty(clientApp)) {
            clientApp = request.getHeader(HttpHeadConsts.REQUEST_HEADER_SERVICE_NAME_KEY);
        }
        if (StringExtUtils.isAnyEmpty(clientApp)) {
            clientApp = ApplicationConfig.SERVICE_NAME;
        }
        return clientApp;
    }

    @Override
    protected String getLoginClientIp(HttpServletRequest webObject) {
        return HttpContextUtils.getIp(request);
    }

    @Override
    protected IUserCache getCurrentUserCache(HttpServletRequest webObject) {
        return (IUserCache) request.getAttribute(HttpHeadConsts.REQUEST_USER_KEY);
    }

    @Override
    protected Long currentUserIdFromHeader(HttpServletRequest webObject) {
        String ret = request.getHeader(HttpHeadConsts.REQUEST_HEADER_USERID_KEY);
        if (!StringUtils.isEmpty(ret)) {
            try {
                return Long.parseLong(ret.trim());
            } catch (Exception e) {
                log.error("Call currentUserIdFromHeader() failed", e);
            }
        }
        return null;
    }

    @Override
    protected IUserCache currentLoginUser(HttpServletRequest webObject) {
        return getCurrentUserCache(request);
    }

    protected IUserCache currentLoginUser() {
        return getCurrentUserCache(request);
    }

    protected String getToken() {
        return getToken(request);
    }

    protected String getLoginClientApp() {
        return getLoginClientApp(request);
    }

    protected String getLoginClientIp() {
        return getLoginClientIp(request);
    }

    protected Long currentUserId() {
        return currentUserId(request);
    }

    protected IUserCache getCurrentUserCache() {
        return getCurrentUserCache(request);
    }

    protected <T> ApiResult<T> invokeFail(String argsMsg, Exception e) {
        return doInvokeFail(argsMsg, e);
    }

    protected <T> ApiResult<T> returnFail(Integer resultCode, String errorMsg) {
        return doReturnFail(resultCode, errorMsg);
    }

    protected <T> ApiResult<T> returnFail(String errorMsg) {
        return doReturnFail(errorMsg);
    }

    protected <T> ApiResult<T> returnFailToken() {
        return doReturnFailToken();
    }

    protected <T> ApiResult<T> returnSuccess(T ret) {
        return doReturnSuccess(ret);
    }

    protected <OUT_T> ApiResult<OUT_T> invokeMethod(Supplier<OUT_T> function) {
        return doInvokeMethod(function, ResultEnum.SUCCESS, null);
    }

    protected <OUT_T> ApiResult<OUT_T> invokeMethod(Supplier<OUT_T> function,
                                                    ResultEnum nullResult,
                                                    String exceptionMsg) {
        return doInvokeMethod(function, nullResult, exceptionMsg);
    }

    protected <IN_T, OUT_T> ApiResult<OUT_T> invokeMethod(Function<IN_T, OUT_T> function,
                                                          IN_T inputArg) {
        return doInvokeMethod(function, inputArg, ResultEnum.SUCCESS, null);
    }

    protected <IN_T, OUT_T> ApiResult<OUT_T> invokeMethod(Function<IN_T, OUT_T> function,
                                                          IN_T inputArg,
                                                          ResultEnum nullResult,
                                                          String exceptionMsg) {
        return doInvokeMethod(function, inputArg, nullResult, exceptionMsg);
    }

}
